import { Card, CardType } from "../cardsystem/card"
import { Sha, Shan, Tao, Jiu } from "../cardsystem/basicCard"
import { Player } from "./player"
import { WaitForPushCardEvent, createDefaultEvent } from '@/store/reactiveStore'
import { Optional } from "../util/common";
import _ from 'lodash'
import { TaoYuanJieYi, WuGuFengDeng, WuXieKeJi, WuZhongShengYou } from "../cardsystem/brilliantness/nodelay";
import { PickPurpose } from "../strategies/BaseSmartBehavior";

const DefaultPromise = <T>(t:T) => new Promise<T>((resolve) => resolve(t));

const VoidPromise = new Promise<void>((resolve) => resolve())

export interface CardUsingEventHandler<T extends Card> {

    card: T,
    player: Player | null

    /**
     * 出牌时
     */
    startCardUse(): Promise<void>,

    /**
     * 指定目标时
     */
    specTarget(): Promise<void>

    /**
     * 等待响应
     */
    needAndWaitForResponse<R extends Card>(requestCardType: CardType<R>): Promise<WaitForPushCardEvent>

    /**
     * 处理所有需要选则的行为 (火攻,反间等)
     * @param canPick 可选范围
     */
    pickAnyOne<R>(canPick: R[]): Promise<Optional<R>>

    /**
     * 目标响应时
     * @param respCard 响应的牌
     */
    afterResponse(respCard: Card[], cancel: boolean): Promise<void>

    /**
     * 计算伤害
     * @param n 预期伤害
     */
    calHurt(): Promise<number>

    /**
     * 结算伤害
     * @param n 扣多少伤害
     */
    settleHurt(n: number): Promise<void>

    /**
     * 玩家濒死
     */
    playerBeingDead(): Promise<void>

    /**
     * 结算后处理
     */
    afterSettle(): Promise<void>
    /**
     * 收尾工作
     */
    afterUsing(): Promise<void>
}


export class EmptyCardUsingEventHandler<T extends Card> implements CardUsingEventHandler<T> {
    card: T
    player: Player | null

    constructor(card: T, player: Player | null) {
        this.card = card
        this.player = player
    }

    startCardUse(): Promise<void> {
        return VoidPromise;
    }

    specTarget(): Promise<void> {
        return VoidPromise;
    }

    needAndWaitForResponse<R extends Card>(requestCardType: CardType<R>): Promise<WaitForPushCardEvent> {
        return DefaultPromise(createDefaultEvent({cancel: true}))
    }

    pickAnyOne<R>(canPick: R[]): Promise<Optional<R>> {
        return DefaultPromise(Optional.empty())
    }

    afterResponse(respCard: Card[], cancel: boolean): Promise<void> {
        return VoidPromise;
    }

    calHurt(): Promise<number> {
        return DefaultPromise(0)
    }

    settleHurt(n: number): Promise<void> {
        return VoidPromise
    }

    playerBeingDead(): Promise<void> {
        return VoidPromise
    }

    afterSettle(): Promise<void> {
        return VoidPromise
    }

    afterUsing(): Promise<void> {
        return VoidPromise
    }
}

export class CardUsingEventWrapper<T extends Card> implements CardUsingEventHandler<T> {

    card: T
    player: Player | null

    cardUsingEventHandler: CardUsingEventHandler<T>

    constructor(cardUsingEventHandler: CardUsingEventHandler<T>) {
        this.cardUsingEventHandler = cardUsingEventHandler
        this.card = cardUsingEventHandler.card
        this.player = cardUsingEventHandler.player
    }

    /**
     * 出牌时
     */
    startCardUse(): Promise<void> {
        return this.cardUsingEventHandler.startCardUse()
    }

    /**
     * 指定目标时
     */
    specTarget(): Promise<void> {
        return this.cardUsingEventHandler.specTarget()
    }

    needAndWaitForResponse<R extends Card>(requestCardType: CardType<R>): Promise<WaitForPushCardEvent> {
        return this.cardUsingEventHandler.needAndWaitForResponse(requestCardType)
    }

    pickAnyOne<R>(canPick: R[]): Promise<Optional<R>> {
        return this.cardUsingEventHandler.pickAnyOne(canPick)
    }

    /**
     * 目标响应时
     * @param respCard 响应的牌
     */
    afterResponse(respCard: Card[], cancel: boolean): Promise<void> {
        return this.cardUsingEventHandler.afterResponse(respCard, cancel)
    }

    /**
     * 计算伤害
     * @param n 预期伤害
     */
    calHurt(): Promise<number> {
        return this.cardUsingEventHandler.calHurt()
    }

    /**
     * 结算伤害
     */
    settleHurt(n: number): Promise<void> {
        return this.cardUsingEventHandler.settleHurt(n)
    }

    /**
     * 玩家濒死
     */
    playerBeingDead(): Promise<void> {
        return this.cardUsingEventHandler.playerBeingDead()
    }

    /**
     * 结算后处理
     */
    afterSettle(): Promise<void> {
        return this.cardUsingEventHandler.afterSettle()
    }

    afterUsing(): Promise<void> {
        return this.cardUsingEventHandler.afterUsing()
    }

}


export interface ResponseHandlerProxy<T extends Card> {

    shouldApply(extendsHandler: CardUsingEventHandler<T>): boolean

    apply(extendsHandler: CardUsingEventHandler<T>): CardUsingEventHandler<T>

}

export interface CardTypeRequestProxyFactory {

    name: string
    createResponseHandlerProxy<T extends Card>(player: Player): ResponseHandlerProxy<T>
}


/**
 * 默认卡牌请求处理器, 只针对目标是当前对象应用,有牌就响应
 */
export const DefaultRequestProxyFactory: CardTypeRequestProxyFactory = {

    name: 'DefaultRequestProxyFactory',

    createResponseHandlerProxy<T extends Card>(player: Player): ResponseHandlerProxy<T> {
        return {
             shouldApply(extendsHandler: CardUsingEventHandler<T>): boolean {
                const sourceCard = extendsHandler.card
                return sourceCard.cardProperties.target != null && sourceCard.cardProperties.target.equals(player)
             },
             apply(extendsHandler: CardUsingEventHandler<T>): CardUsingEventHandler<T> {

                class DefaultRequestEvent extends CardUsingEventWrapper<T> {

                    constructor(cardUsingEventHandler: CardUsingEventHandler<T>, player: Player) {
                        super(cardUsingEventHandler)
                        this.player = player
                    }

                    async needAndWaitForResponse<R extends Card>(requestCardType: CardType<R>): Promise<WaitForPushCardEvent> {
                        const res = this.cardUsingEventHandler.needAndWaitForResponse(requestCardType)
                        const result = await res
                        if (!result.cancel) {
                            return res
                        }
                        if ((this.card instanceof WuZhongShengYou || this.card instanceof TaoYuanJieYi ||  this.card instanceof WuGuFengDeng) && requestCardType.name == WuXieKeJi.name) {
                            return res
                        }

                        // 目标玩家是否有该类型牌
                        const target = this.card.cardProperties.target
                        const defaultRes = DefaultPromise( createDefaultEvent({cancel: true}))

                        if (this.card.cardProperties.cancelEffect) {
                            return defaultRes
                        }
                        if (!target) {
                            return defaultRes
                        }
                        const matchesCards = target.handCardAreas.matchesHandCards(requestCardType)
                        if (matchesCards.length == 0) {
                            return defaultRes
                        }
                        const options = {canPickCards: matchesCards, canPickMin: 1, canPickMax: 1, pickPurpose: PickPurpose.DROPPING, currentPlayer: target, resonCard: this.card}
                        const waitRes = target.behaviorStragy.waitForPickCard(options)
                        const waitResult = await waitRes
                        if (!waitResult.cancel && waitResult.selectedCards.length > 0) {
                            for(const c of waitResult.selectedCards) {
                                await c.response(this.card)
                            }
                        }
                        return waitRes
                    }

                    async pickAnyOne<R>(canPick: R[]): Promise<Optional<R>> {
                        const res = this.cardUsingEventHandler.pickAnyOne(canPick)
                        const result = await res
                        if (result.isPresent()) {
                            return res
                        }
                        if (canPick.length < 1) {
                            return res
                        }

                        const randomPickIndex = _.random(0, canPick.length-1)
                        const op = new Optional(canPick[randomPickIndex])
                        return DefaultPromise(op)
                    }

                    async playerBeingDead(): Promise<void> {
                        const target  = this.cardUsingEventHandler.card.cardProperties.target
                        const player = this.player
                        if ( target && player && player.equals(target)) {
                            while(player.isBeingDead()) {
                                this.cardUsingEventHandler.playerBeingDead()
                                const gm = player.gameManager
                                gm.appendLog(`${player.name} 濒死状态,请求酒...`)
                                let respRes = await this.needAndWaitForResponse(Jiu)
                                if (respRes.cancel) {
                                    gm.appendLog(`${player.name} 濒死状态,请求桃...`)
                                    respRes = await this.needAndWaitForResponse(Tao)
                                    if (respRes.cancel) {
                                        gm.appendLog(`${player.name} 目标已死亡`)
                                        player.dead()
                                        break
                                    } else {
                                        const respCard = respRes.selectedCards[0]
                                        gm.appendLog(`${player.name} 响应一张 ${respCard.colorCN()} ${respCard.numberCN()} 的 ${respCard.info()}`)
                                    }
                                } else {
                                    const respCard = respRes.selectedCards[0]
                                    gm.appendLog(`${player.name} 响应一张 ${respCard.colorCN()} ${respCard.numberCN()} 的 ${respCard.info()}`)
                                }
                            }
                        } else {
                            this.cardUsingEventHandler.playerBeingDead()
                        }
                    }
                }

                return new DefaultRequestEvent(extendsHandler, player)
             }
        }
    }
}

